/*
 * This file is part of TradeHelper library.
 *
 * TradeHelper library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * TradeHelper library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with TradeHelper library.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.rag.forum.pages;

import com.alee.extended.background.ColorBackgroundPainter;
import com.alee.extended.breadcrumb.WebBreadcrumbToggleButton;
import com.alee.extended.buttongroup.ButtonGroupListener;
import com.alee.extended.drag.ProxyDropHandler;
import com.alee.extended.image.WebImage;
import com.alee.extended.layout.AlignLayout;
import com.alee.extended.layout.ToolbarLayout;
import com.alee.extended.layout.VerticalFlowLayout;
import com.alee.extended.listener.EmptyMouseAdapter;
import com.alee.extended.panel.*;
import com.alee.laf.StyleConstants;
import com.alee.laf.button.WebButton;
import com.alee.laf.button.WebToggleButton;
import com.alee.laf.combobox.WebComboBox;
import com.alee.laf.combobox.WebComboBoxCellRenderer;
import com.alee.laf.combobox.WebComboBoxElement;
import com.alee.laf.label.WebLabel;
import com.alee.laf.panel.WebPanel;
import com.alee.laf.progressbar.WebProgressBar;
import com.alee.laf.scroll.WebScrollPane;
import com.alee.laf.separator.WebSeparator;
import com.alee.managers.hotkey.Hotkey;
import com.alee.managers.hotkey.HotkeyManager;
import com.alee.managers.settings.SettingsManager;
import com.alee.managers.tooltip.TooltipManager;
import com.alee.managers.tooltip.TooltipWay;
import com.alee.utils.SwingUtils;
import com.alee.utils.TextUtils;
import com.rag.core.ForumType;
import com.rag.core.Item;
import com.rag.core.ItemData;
import com.rag.core.SingleTopicData;
import com.rag.forum.ui.ItemDropList;
import com.rag.forum.ui.ItemField;
import com.rag.forum.ui.ItemListener;
import com.rag.forum.ui.ItemSelectionListener;
import com.rag.managers.FavoritesManager;
import com.rag.managers.ForumManager;
import com.rag.managers.RagManager;
import com.rag.managers.favorites.FavoritesListener;
import com.rag.managers.forum.DataLoadListener;
import com.rag.utils.RagUtils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * User: mgarin Date: 12.04.12 Time: 17:20
 */

public class ForumPage extends WebPanel
{
    private static ImageIcon addIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/add.png" ) );

    private static ImageIcon itemFilterIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/filter/byItem.png" ) );
    private static ImageIcon userFilterIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/filter/byUser.png" ) );
    private static ImageIcon textFilterIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/filter/byText.png" ) );

    private static ImageIcon includeFilterIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/include.png" ) );
    private static ImageIcon excludeFilterIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/exclude.png" ) );

    private static ImageIcon noneSortIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/sort/none.png" ) );
    private static ImageIcon topicSortIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/sort/topic.png" ) );

    private static ImageIcon amountIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/amount.png" ) );
    private static ImageIcon selectedAmountIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/selectedAmount.png" ) );

    private static ImageIcon contentIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/content.png" ) );
    private static ImageIcon groupIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/group.png" ) );
    private static ImageIcon wrapIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/wrap.png" ) );

    private static ImageIcon itemIdIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/itemId.png" ) );

    private static ImageIcon reloadIcon =
            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/reload.png" ) );

    //    private static ImageIcon favoriteIcon =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/favorite.png" ) );
    //    private static ImageIcon nonfavoriteIcon =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/nonfavorite.png" ) );

    //    private static ImageIcon replyIcon =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/reply.png" ) );

    //    private static ImageIcon userIcon =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/user.png" ) );
    //    private static ImageIcon pmIcon =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/pm.png" ) );

    //    private static ImageIcon info24 =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/info24.png" ) );
    //    private static ImageIcon closed24 =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/closed24.png" ) );
    //    private static ImageIcon guild24 =
    //            new ImageIcon ( ForumPage.class.getResource ( "icons/forum/guild24.png" ) );

    // Последние загруженные данные о топиках
    private List<SingleTopicData> topicsData = null;

    // Тип форума, отображаемого данной страницей
    private ForumType forumType;

    // Идёт ли загрузка данных в данный момент
    private boolean loadingData = false;

    // Элементы интерфейса

    private WebPanel container;
    private CenterPanel waitPanel;
    private WebOverlay loadOverlay;

    private WebBreadcrumbToggleButton menuButton;

    private WebPanel settingsPanel;

    private WebToggleButton ifb;
    private WebToggleButton ufb;
    private WebToggleButton tfb;

    private WebToggleButton includeFilter;
    private WebToggleButton excludeFilter;

    private WebToggleButton doNotSort;
    private WebToggleButton sortByTopic;

    private WebToggleButton groupItems;
    private WebToggleButton wrapItems;

    private WebToggleButton showItemId;

    private WebComboBox topicsShowAmount;
    //    private WebToggleButton loadTopicContent;
    private WebButton reload;

    private WebPanel filtersPanel;

    private WebCollapsiblePane itemFilterPane;
    private ItemField itemSearchField;
    private WebLabel itemFilterPaneTitle;
    private ItemDropList itemFilterList;

    private WebCollapsiblePane userFilterPane;
    private WebCollapsiblePane textFilterPane;

    private WebPanel contentPanel;
    private WebScrollPane contentScroll;

    private WebLabel progressLabel;
    private WebProgressBar progressBar;

    public ForumPage ( final ForumType forumType, WebBreadcrumbToggleButton menuButton )
    {
        super ();

        this.forumType = forumType;
        this.menuButton = menuButton;

        final String pageKey = "ForumPage." + forumType + ".";

        //  Overlay загрузки

        container = new WebPanel ();

        waitPanel = new CenterPanel ( new WheelImage (), true, true );
        waitPanel.setVisible ( false );
        waitPanel.setBackgroundPainter (
                new ColorBackgroundPainter ( new Color ( 128, 128, 128, 128 ) ) );
        EmptyMouseAdapter.install ( waitPanel );

        loadOverlay = new WebOverlay ( container, waitPanel );
        add ( loadOverlay, BorderLayout.CENTER );

        //

        WebPanel northPanel = new WebPanel ();
        container.add ( northPanel, BorderLayout.NORTH );


        // Тулбар настроек
        settingsPanel = new WebPanel ( true );
        settingsPanel.setMargin ( 4 );
        settingsPanel.setShadeWidth ( 0 );
        settingsPanel.setDrawSides ( false, false, true, false );
        settingsPanel.setLayout ( new ToolbarLayout ( 4, ToolbarLayout.HORIZONTAL ) );
        northPanel.add ( settingsPanel, BorderLayout.NORTH );

        ifb = WebToggleButton.createIconWebButton ( itemFilterIcon );
        TooltipManager.setTooltip ( ifb, "Фильтрация по итемам" );
        SettingsManager.registerComponent ( ifb, pageKey + "itemFilterOn", false );
        ifb.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                filtersPanel.removeAll ();
                if ( ifb.isSelected () )
                {
                    filtersPanel.add ( itemFilterPane );
                }
                filtersPanel.revalidate ();
                filtersPanel.repaint ();

                showForumPageContent ();
            }
        } );

        ufb = WebToggleButton.createIconWebButton ( userFilterIcon );
        TooltipManager.setTooltip ( ufb, "Фильтрация по пользователям" );
        SettingsManager.registerComponent ( ufb, pageKey + "userFilterOn", false );
        ufb.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                filtersPanel.removeAll ();
                if ( ufb.isSelected () )
                {
                    filtersPanel.add ( userFilterPane );
                }
                filtersPanel.revalidate ();
                filtersPanel.repaint ();

                showForumPageContent ();
            }
        } );

        tfb = WebToggleButton.createIconWebButton ( textFilterIcon );
        TooltipManager.setTooltip ( tfb, "Фильтрация по тексту" );
        SettingsManager.registerComponent ( tfb, pageKey + "textFilterOn", false );
        tfb.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                filtersPanel.removeAll ();
                if ( tfb.isSelected () )
                {
                    filtersPanel.add ( textFilterPane );
                }
                filtersPanel.revalidate ();
                filtersPanel.repaint ();

                showForumPageContent ();
            }
        } );

        final WebButtonGroup fg = new WebButtonGroup ( true, ifb, ufb, tfb );
        fg.setButtonsDrawFocus ( false );
        fg.setUnselectable ( true );
        settingsPanel.add ( fg );

        includeFilter = WebToggleButton.createIconWebButton ( includeFilterIcon );
        includeFilter.setEnabled ( fg.isAnySelected () );
        TooltipManager
                .setTooltip ( includeFilter, "Показывать только итемы по выбранным фильтрам" );
        SettingsManager.registerComponent ( includeFilter, pageKey + "includeFilter", true );
        includeFilter.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                showForumPageContent ();
            }
        } );

        excludeFilter = WebToggleButton.createIconWebButton ( excludeFilterIcon );
        excludeFilter.setEnabled ( fg.isAnySelected () );
        TooltipManager
                .setTooltip ( excludeFilter, "Исключать итемы, попадающие под выбранные фильтры" );
        SettingsManager.registerComponent ( excludeFilter, pageKey + "excludeFilter", false );
        excludeFilter.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                showForumPageContent ();
            }
        } );

        fg.getButtonGroup ().addButtonGroupListener ( new ButtonGroupListener ()
        {
            public void selectionChanged ()
            {
                includeFilter.setEnabled ( fg.isAnySelected () );
                excludeFilter.setEnabled ( fg.isAnySelected () );
            }
        } );

        WebButtonGroup ftg = new WebButtonGroup ( true, includeFilter, excludeFilter );
        ftg.setButtonsDrawFocus ( false );
        settingsPanel.add ( ftg );

        //        settingsPanel.add ( new WebSeparator ( WebSeparator.VERTICAL ) );
        //
        //        doNotSort = WebToggleButton.createIconWebButton ( noneSortIcon );
        //        SettingsManager.registerComponent ( doNotSort, pageKey + "noneGroup", false );
        //        TooltipManager.setTooltip ( doNotSort, "Не группировать данные" );
        //        doNotSort.addActionListener ( new ActionListener ()
        //        {
        //            public void actionPerformed ( ActionEvent e )
        //            {
        //                showForumPageContent ();
        //            }
        //        } );
        //
        //        sortByTopic = WebToggleButton.createIconWebButton ( topicSortIcon );
        //        SettingsManager.registerComponent ( sortByTopic, pageKey + "topicGroup", true );
        //        TooltipManager.setTooltip ( sortByTopic, "Группировать данные по топикам" );
        //        sortByTopic.addActionListener ( new ActionListener ()
        //        {
        //            public void actionPerformed ( ActionEvent e )
        //            {
        //                showForumPageContent ();
        //            }
        //        } );
        //
        //        WebButtonGroup sg = new WebButtonGroup ( true, doNotSort, sortByTopic );
        //        sg.setButtonsDrawFocus ( false );
        //        settingsPanel.add ( sg );

        settingsPanel.add ( new WebSeparator ( WebSeparator.VERTICAL ) );

        groupItems = new WebToggleButton ( groupIcon );
        groupItems.setRound ( StyleConstants.smallRound );
        groupItems.setDrawFocus ( false );
        TooltipManager.setTooltip ( groupItems, "Группировать итемы по типу" );
        SettingsManager.registerComponent ( groupItems, pageKey + "groupResults", true );
        groupItems.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                showForumPageContent ();
            }
        } );

        wrapItems = new WebToggleButton ( wrapIcon );
        wrapItems.setRound ( StyleConstants.smallRound );
        wrapItems.setDrawFocus ( false );
        TooltipManager.setTooltip ( wrapItems, "Показывать каждый итем на отдельной строке" );
        SettingsManager.registerComponent ( wrapItems, pageKey + "wrapResults", true );
        wrapItems.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                // Нет необходимости обновлять пока идёт загрузка
                if ( loadingData )
                {
                    return;
                }

                // Обновляем настройки лэйаутов топиков
                for ( Component component : contentPanel.getComponents () )
                {
                    if ( component instanceof TopicContentPanel )
                    {
                        TopicContentPanel tcp = ( TopicContentPanel ) component;
                        tcp.setWrapItems ( wrapItems.isSelected () );
                    }
                }
            }
        } );

        showItemId = new WebToggleButton ( itemIdIcon );
        showItemId.setRound ( StyleConstants.smallRound );
        showItemId.setDrawFocus ( false );
        TooltipManager.setTooltip ( showItemId, "Показывать ID итемов из базы" );
        SettingsManager.registerComponent ( showItemId, pageKey + "showItemId", false );
        showItemId.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                showForumPageContent ();
            }
        } );

        settingsPanel.add ( groupItems );
        settingsPanel.add ( wrapItems );
        settingsPanel.add ( showItemId );

        //

        topicsShowAmount = new WebComboBox ( new Integer[]{ 25, 50, 75, 100, 125, 150, 175, 200 } );
        TooltipManager
                .setTooltip ( topicsShowAmount, "Количество последних топиков для обработки" );
        SettingsManager.registerComponent ( topicsShowAmount, pageKey + "showAmount", 1 );
        topicsShowAmount.setDrawFocus ( false );
        topicsShowAmount.setRenderer ( new WebComboBoxCellRenderer ( topicsShowAmount )
        {
            public Component getListCellRendererComponent ( JList list, Object value, int index,
                                                            boolean isSelected,
                                                            boolean cellHasFocus )
            {
                WebComboBoxElement renderer = ( WebComboBoxElement ) super
                        .getListCellRendererComponent ( list, value, index, isSelected,
                                cellHasFocus );
                renderer.setIcon ( index != -1 && isSelected ? selectedAmountIcon : amountIcon );
                renderer.setText ( value + " топиков" );
                return renderer;
            }
        } );
        topicsShowAmount.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                loadForumPageContent ();
            }
        } );
        settingsPanel.add ( topicsShowAmount, ToolbarLayout.END );

        //        loadTopicContent = WebToggleButton.createIconWebButton ( contentIcon );
        //        loadTopicContent.setDrawFocus ( false );
        //        TooltipManager.setTooltip ( loadTopicContent, "Загружать содержимое топиков" );
        //        SettingsManager.registerComponent ( loadTopicContent, pageKey + "loadContent", true );
        //        loadTopicContent.addActionListener ( new ActionListener ()
        //        {
        //            public void actionPerformed ( ActionEvent e )
        //            {
        //                // loadForumPageContent ();
        //            }
        //        } );
        //        settingsPanel.add ( loadTopicContent, ToolbarLayout.END );

        reload = WebButton.createIconWebButton ( reloadIcon );
        HotkeyManager.registerHotkey ( reload, Hotkey.F5 );
        TooltipManager.setTooltip ( reload, "Перезагрузить список топиков" )
                .setHotkeyLocation ( SwingConstants.LEADING );
        reload.setDrawFocus ( false );
        reload.addActionListener ( new ActionListener ()
        {
            public void actionPerformed ( ActionEvent e )
            {
                loadForumPageContent ();
            }
        } );
        settingsPanel.add ( reload, ToolbarLayout.END );


        // Filters
        filtersPanel = new WebPanel ( new GridLayout ( 1, 3, 0, 0 ) );
        filtersPanel.setMargin ( 5, 5, 0, 5 );
        northPanel.add ( filtersPanel, BorderLayout.CENTER );

        // Item filter
        createItemFilterPane ( pageKey, menuButton );

        // User filter
        createUserFilterPane ( pageKey );

        // Word filter
        createTextFilterPane ( pageKey );

        // Для авторазворачивания всех панелей
        final List<WebCollapsiblePane> panes =
                Arrays.asList ( itemFilterPane, userFilterPane, textFilterPane );
        CollapsiblePaneAdapter collapsiblePaneAdapter = new CollapsiblePaneAdapter ()
        {
            public void expanding ( WebCollapsiblePane webCollapsiblePane )
            {
                for ( WebCollapsiblePane pane : panes )
                {
                    pane.setExpanded ( true );
                }
            }

            public void collapsing ( WebCollapsiblePane webCollapsiblePane )
            {
                for ( WebCollapsiblePane pane : panes )
                {
                    pane.setExpanded ( false );
                }
            }
        };
        itemFilterPane.addCollapsiblePaneListener ( collapsiblePaneAdapter );
        userFilterPane.addCollapsiblePaneListener ( collapsiblePaneAdapter );
        textFilterPane.addCollapsiblePaneListener ( collapsiblePaneAdapter );


        // Content
        contentPanel = new WebPanel ();
        contentPanel.setFocusable ( true );
        contentPanel.addMouseListener ( new MouseAdapter ()
        {
            public void mousePressed ( MouseEvent e )
            {
                contentPanel.requestFocusInWindow ();
            }
        } );
        contentScroll = new WebScrollPane ( contentPanel, false );

        WebPanel contentPanelBorder = new WebPanel ( true, contentScroll );
        contentPanelBorder.setWebColored ( false );
        contentPanelBorder.setShadeWidth ( 5 );
        contentPanelBorder.setMargin ( 0 );
        contentPanelBorder.add ( contentScroll, BorderLayout.CENTER );
        container.add ( new BorderPanel ( contentPanelBorder, 0, 5, 5, 5 ), BorderLayout.CENTER );


        // Ддя прослушивания изменения избранных топиков
        final FavoritesListener favoritesListener = new FavoritesListener ()
        {
            public void favoriteTopicAdded ( SingleTopicData added )
            {
                setFavorite ( added, true );
            }

            public void favoriteTopicsUpdated ( List<SingleTopicData> updated )
            {
                //
            }

            public void favoriteTopicRemoved ( SingleTopicData removed )
            {
                setFavorite ( removed, false );
            }

            private void setFavorite ( SingleTopicData data, boolean favorite )
            {
                for ( Component component : contentPanel.getComponents () )
                {
                    if ( component instanceof TopicContentPanel )
                    {
                        TopicContentPanel tcp = ( TopicContentPanel ) component;
                        if ( data.equals ( tcp.getTopicData () ) )
                        {
                            tcp.setFavorite ( favorite );
                        }
                    }
                }
            }
        };
        FavoritesManager.addFavoritesListener ( favoritesListener );


        // Для начальной загрузки
        reload.doClick ();
    }

    private void createItemFilterPane ( String pageKey, AbstractButton pageButton )
    {
        itemFilterPane = new WebCollapsiblePane ();
        itemFilterPane.setShadeWidth ( 5 );
        itemFilterPane.setAnimate ( false );
        SettingsManager.registerComponent ( itemFilterPane, pageKey + "itemFilterExpanded", true );
        if ( ifb.isSelected () )
        {
            filtersPanel.add ( itemFilterPane );
        }

        itemSearchField = new ItemField ();
        TooltipManager.setTooltip ( itemSearchField, "Быстрый поиск итемов", TooltipWay.right );
        itemSearchField.setColumns ( 0 );
        itemSearchField.setRound ( 0 );
        itemSearchField.setFont ( itemSearchField.getFont ().deriveFont ( 10f ) );
        final WebImage search = new WebImage ( ForumPage.class, "icons/forum/search.png" );
        final WebImage esearch = new WebImage ( ForumPage.class, "icons/forum/esearch.png" );
        itemSearchField.setTrailingComponent ( search );
        itemSearchField.addFocusListener ( new FocusListener ()
        {
            public void focusGained ( FocusEvent e )
            {
                itemSearchField.setColumns ( 20 );
                itemSearchField.setTrailingComponent ( esearch );
                itemFilterPane.getHeaderPanel ().revalidate ();
            }

            public void focusLost ( FocusEvent e )
            {
                itemSearchField.setColumns ( 0 );
                itemSearchField.setTrailingComponent ( search );
                itemFilterPane.getHeaderPanel ().revalidate ();
            }
        } );

        itemFilterPaneTitle = new WebLabel ();
        itemFilterPaneTitle.setIcon ( itemFilterIcon );
        itemFilterPaneTitle.setText ( "Фильтрация по итемам" );
        itemFilterPaneTitle.setHorizontalAlignment ( WebLabel.CENTER );
        itemFilterPaneTitle.putClientProperty ( GroupPanel.FILL_CELL, true );
        itemFilterPaneTitle.setMargin ( 4 );

        itemFilterPane
                .setTitleComponent ( new GroupPanel ( 4, itemSearchField, itemFilterPaneTitle ) );

        itemFilterList = new ItemDropList ();
        itemFilterList.setVisibleRowCount ( 3 );
        itemFilterList.setDropText ( "Перетащите сюда любые итемы" );
        itemFilterList.addItems ( RagManager.getItems ( TextUtils.stringToList (
                SettingsManager.getString ( "ForumPage." + forumType + ".itemsFilter" ), "," ) ) );
        itemFilterList.addItemSelectionListener ( new ItemSelectionListener ()
        {
            public void selectionChanged ( List<Item> items )
            {
                showForumPageContent ();

                SettingsManager.set ( "ForumPage." + forumType + ".itemsFilter",
                        TextUtils.listToString ( itemFilterList.getItemIds (), "," ) );
            }
        } );
        itemSearchField.addItemListener ( new ItemListener ()
        {
            public void itemSelected ( Item item )
            {
                itemFilterPane.expand ();
                itemFilterList.addItem ( item );
                itemSearchField.clear ();
                itemSearchField.requestFocusInWindow ();
            }
        } );
        itemFilterPane.setContent ( itemFilterList.getView ( false ) );

        // Для передачи драга списку
        ProxyDropHandler proxyDropHandler = new ProxyDropHandler ( itemFilterList )
        {
            public boolean importData ( TransferSupport info )
            {
                boolean imported = super.importData ( info );
                if ( imported )
                {
                    itemFilterPane.expand ();
                }
                return imported;
            }
        };
        itemFilterPane.setTransferHandler ( proxyDropHandler );
        pageButton.setTransferHandler ( proxyDropHandler );
    }

    private void createUserFilterPane ( String pageKey )
    {
        userFilterPane = new WebCollapsiblePane ( "Фильтрация по пользователям", userFilterIcon );
        userFilterPane.setShadeWidth ( 5 );
        userFilterPane.setAnimate ( false );
        WebLabel title = ( WebLabel ) userFilterPane.getTitleComponent ();
        title.setHorizontalAlignment ( WebLabel.CENTER );
        title.setMargin ( 4 );
        SettingsManager.registerComponent ( userFilterPane, pageKey + "userFilterExpanded", true );
        if ( ufb.isSelected () )
        {
            filtersPanel.add ( userFilterPane );
        }
    }

    private void createTextFilterPane ( String pageKey )
    {
        textFilterPane = new WebCollapsiblePane ( "Фильтрация по тексту", textFilterIcon );
        textFilterPane.setShadeWidth ( 5 );
        textFilterPane.setAnimate ( false );
        WebLabel title = ( WebLabel ) textFilterPane.getTitleComponent ();
        title.setHorizontalAlignment ( WebLabel.CENTER );
        title.setMargin ( 4 );
        SettingsManager.registerComponent ( textFilterPane, pageKey + "textFilterExpanded", true );
        if ( tfb.isSelected () )
        {
            filtersPanel.add ( textFilterPane );
        }
    }

    /**
     * Загружает топики с форума с последующим обновлением отображения
     */

    private void loadForumPageContent ()
    {
        int pagesToLoad = Integer.parseInt ( topicsShowAmount.getSelectedItem ().toString () ) /
                ForumManager.topicsPerPage - 1;
        loadForumPageContent ( 0, pagesToLoad );
    }

    private void loadForumPageContent ( final int startPage, final int endPage )
    {
        // Отмечаем начало загрузки данных
        loadingData = true;

        // Показываем прогресс загрузки
        showForumPageLoad ();

        // Блокируем контролы
        enableControls ( false );

        new Thread ( new Runnable ()
        {
            public void run ()
            {
                // Загружаем и парсим топики
                DataLoadListener dll = new DataLoadListener ()
                {
                    public void stateUpdated ( final String state, final float progress )
                    {
                        SwingUtils.invokeLater ( new Runnable ()
                        {
                            public void run ()
                            {
                                // Обновляем состояние загрузки
                                progressLabel.setText ( state );
                                progressBar.setValue ( Math.round ( progress ) );
                                menuButton.setProgress ( progress / 100 );
                            }
                        } );
                    }
                };
                topicsData = ForumManager.loadForumData ( forumType, startPage, endPage, dll );

                SwingUtils.invokeLater ( new Runnable ()
                {
                    public void run ()
                    {
                        // Отмечаем конец загрузки данных
                        loadingData = false;

                        // Показываем загруженные данные
                        showForumPageContent ();
                    }
                } );
            }
        } ).start ();
    }

    /**
     * Обновляет отображение по данным
     */

    private void showForumPageLoad ()
    {
        // Очищаем панель
        contentPanel.removeAll ();
        contentPanel.setLayout ( new AlignLayout () );

        // Добавляем панель прогресса
        WebPanel progressPanel = new WebPanel ();
        contentPanel.add ( progressPanel, "0,0" );

        progressLabel = new WebLabel ( "", WebLabel.CENTER );
        progressPanel.add ( progressLabel, BorderLayout.NORTH );

        progressBar = new WebProgressBar ( WebProgressBar.HORIZONTAL, 0, 100 );
        progressPanel.add ( progressBar, BorderLayout.CENTER );

        // Обновляем панель
        contentPanel.revalidate ();
        contentPanel.repaint ();
    }

    private void showForumPageContent ()
    {
        // Нет необходимости обновлять пока идёт загрузка
        if ( loadingData )
        {
            return;
        }

        // Показываем загрузку интерфейса
        waitPanel.setVisible ( true );

        // Фильтруем данные
        final List<SingleTopicData> topics = getFilteredTopics ();

        if ( topics.size () > 0 )
        {
            // todo Другой вариант просмотра - без группировки итемов по топикам (общий список)

            // Переносим массивные действия в отдельный поток
            new Thread ( new Runnable ()
            {
                public void run ()
                {
                    // Создаём панели с содержимым
                    final List<WebPanel> panels = new ArrayList<WebPanel> ();
                    int i = 1;
                    for ( SingleTopicData topicData : topics )
                    {
                        panels.add ( new TopicContentPanel ( forumType, topicData, topicsData,
                                groupItems.isSelected (), wrapItems.isSelected (),
                                showItemId.isSelected (), true ) );
                        i++;
                    }

                    SwingUtils.invokeLater ( new Runnable ()
                    {
                        public void run ()
                        {
                            // Очищаем панель
                            contentPanel.removeAll ();

                            // Добавляем созданные панели
                            contentPanel.setLayout ( new VerticalFlowLayout ( 0 ) );
                            contentPanel.add ( panels );

                            // Обновляем панель
                            contentPanel.revalidate ();
                            contentPanel.repaint ();

                            // Разблокируем контролы
                            enableControls ( true );

                            // Прячем загрузку интерфейса
                            waitPanel.setVisible ( false );
                        }
                    } );
                }
            } ).start ();
        }
        else
        {
            // Очищаем панель
            contentPanel.removeAll ();

            // Добавляем сообщение о том, что ничего не найдено
            contentPanel.setLayout ( new AlignLayout () );
            WebLabel info = new WebLabel ( "По заданным фильтрам ничего не найдено",
                    TopicContentPanel.info24 );
            contentPanel.add ( info, "0,0" );

            // Обновляем панель
            contentPanel.revalidate ();
            contentPanel.repaint ();

            // Разблокируем контролы
            enableControls ( true );
        }
    }

    private List<SingleTopicData> getFilteredTopics ()
    {
        final List<SingleTopicData> topics = new ArrayList<SingleTopicData> ();
        boolean include = includeFilter.isSelected ();
        if ( topicsData != null )
        {
            if ( ifb.isSelected () && itemFilterList.getItems ().size () > 0 )
            {
                // Фильтрация по выбранным итемам
                List<Item> filters = itemFilterList.getItems ().getKeys ();
                List<SingleTopicData> copyData = new ArrayList<SingleTopicData> ();
                copyData.addAll ( topicsData );
                for ( SingleTopicData topic : copyData )
                {
                    // Клонируем даные по каждому топику и удаляем не проходящие фильтр
                    SingleTopicData filtered = topic.clone ();
                    List<ItemData> parsedItems = filtered.getParsedItems ();
                    for ( int i = parsedItems.size () - 1; i >= 0; i-- )
                    {
                        ItemData itemData = parsedItems.get ( i );
                        if ( !RagUtils.contains ( filters, itemData.getItemId () ) )
                        {
                            boolean contains = false;
                            if ( itemData.getCardIds () != null )
                            {
                                for ( String cardId : itemData.getCardIds () )
                                {
                                    if ( RagUtils.contains ( filters, cardId ) )
                                    {
                                        contains = true;
                                        break;
                                    }
                                }
                            }
                            if ( include && !contains || !include && contains )
                            {
                                parsedItems.remove ( i );
                            }
                        }
                        else if ( !include )
                        {
                            parsedItems.remove ( i );
                        }
                    }
                    // Если остались итемы, значит фильтр пропустил топик
                    if ( parsedItems.size () > 0 )
                    {
                        topics.add ( filtered );
                    }
                }
            }
            else
            {
                topics.addAll ( topicsData );
            }
        }
        return topics;
    }

    private void enableControls ( boolean enabled )
    {
        menuButton.setShowProgress ( !enabled );
        topicsShowAmount.setEnabled ( enabled );
        // loadTopicContent.setEnabled ( enabled );
        reload.setEnabled ( enabled );
    }

    //    public static WebPanel createTopicContentPanel ( final ForumType forumType,
    //                                                     final SingleTopicData topicData,
    //                                                     List<SingleTopicData> topicsData,
    //                                                     boolean groupItems, boolean wrapItems,
    //                                                     boolean showItemId, boolean showTopicNumber )
    //    {
    //        final WebCollapsiblePane topicContent = new WebCollapsiblePane ();
    //        topicContent.setAnimate ( false );
    //        topicContent.setWebColored ( false );
    //        topicContent.setShadeWidth ( 0 );
    //        topicContent.setDrawSides ( false, false, true, false );
    //        topicContent.setExpanded ( isExpanded ( forumType, topicData.getId () ) );
    //        topicContent.addCollapsiblePaneListener ( new CollapsiblePaneAdapter ()
    //        {
    //            public void expanded ( WebCollapsiblePane pane )
    //            {
    //                setExpanded ( forumType, topicData.getId (), true );
    //            }
    //
    //            public void collapsed ( WebCollapsiblePane pane )
    //            {
    //                setExpanded ( forumType, topicData.getId (), false );
    //            }
    //        } );
    //
    //        final WebPanel topicTitlePanel = new WebPanel ();
    //        topicTitlePanel.setOpaque ( false );
    //        topicTitlePanel.setMargin ( 5 );
    //        topicContent.setTitleComponent ( topicTitlePanel );
    //
    //        // Кнопка добавления в избранное
    //        final WebToggleButton favorite = new WebToggleButton ();
    //        favorite.setIcon ( nonfavoriteIcon );
    //        favorite.setSelectedIcon ( favoriteIcon );
    //        favorite.setUndecorated ( true );
    //        favorite.setLeftRightSpacing ( 0 );
    //
    //        // todo Memory leak
    //        favorite.setSelected ( FavoritesManager.isFavorite ( topicData ) );
    //        final FavoritesListener favoritesListener = new FavoritesListener ()
    //        {
    //            public void favoriteTopicAdded ( SingleTopicData added )
    //            {
    //                if ( added.equals ( topicData ) )
    //                {
    //                    favorite.setSelected ( true );
    //                }
    //            }
    //
    //            public void favoriteTopicsUpdated ( List<SingleTopicData> updated )
    //            {
    //                //
    //            }
    //
    //            public void favoriteTopicRemoved ( SingleTopicData removed )
    //            {
    //                if ( removed.equals ( topicData ) )
    //                {
    //                    favorite.setSelected ( false );
    //                }
    //            }
    //        };
    //        FavoritesManager.addFavoritesListener ( favoritesListener );
    //
    //        favorite.addActionListener ( new ActionListener ()
    //        {
    //            public void actionPerformed ( ActionEvent e )
    //            {
    //                if ( favorite.isSelected () )
    //                {
    //                    FavoritesManager.addFavoriteTopic ( topicData );
    //                }
    //                else
    //                {
    //                    FavoritesManager.removeFavoriteTopic ( topicData );
    //                }
    //            }
    //        } );
    //
    //        // Ссылка на топик с его названием
    //        WebLinkLabel topicTitle = RagUtils.createTopicInfoLink ( topicData );
    //
    //        // Кол-во ответов на топик
    //        WebLabel replyCount = new WebLabel (
    //                topicData.getReplyCount () != null && topicData.getReplyCount () > 0 ?
    //                        "" + topicData.getReplyCount () : "нет", replyIcon );
    //
    //        // Определяем номер топика среди остальных
    //        final String topicNumberText;
    //        if ( showTopicNumber )
    //        {
    //            int tn = 0;
    //            for ( int i = 0; i < topicsData.size (); i++ )
    //            {
    //                if ( topicsData.get ( i ).getId ().equals ( topicData.getId () ) )
    //                {
    //                    tn = i + 1;
    //                    break;
    //                }
    //            }
    //            topicNumberText = showTopicNumber ? ( tn + "." ) : "";
    //        }
    //        else
    //        {
    //            topicNumberText = "";
    //        }
    //
    //        // Заголовок топика
    //        if ( groupItems )
    //        {
    //            WebLabel number = new WebLabel ( topicNumberText, WebLabel.RIGHT )
    //            {
    //                public Dimension getPreferredSize ()
    //                {
    //                    Dimension ps = super.getPreferredSize ();
    //                    ps.width = 80 - topicTitlePanel.getMargin ().left;
    //                    return ps;
    //                }
    //            };
    //            topicTitlePanel.add ( new GroupPanel ( 4, favorite, SwingUtils.boldFont ( number ),
    //                    new WhiteSpace ( 8, WhiteSpace.HORIZONTAL ), topicTitle,
    //                    SwingUtils.boldFont ( replyCount ) ), BorderLayout.WEST );
    //        }
    //        else
    //        {
    //            topicTitlePanel.add ( new GroupPanel ( 4, favorite,
    //                    SwingUtils.boldFont ( new WebLabel ( topicNumberText ) ), topicTitle,
    //                    replyCount ), BorderLayout.WEST );
    //        }
    //
    //        // Ссылка на профиль автора топика
    //        WebLinkLabel userInfo = RagUtils.createUserInfo ( topicData.getUser () );
    //        topicTitlePanel.add ( SwingUtils.boldFont ( userInfo ), BorderLayout.EAST );
    //
    //        // Список итемов
    //        JComponent content = createParsedItemsList ( topicData, groupItems, wrapItems, showItemId );
    //        if ( topicData.getTopicType ().equals ( TopicType.closed ) )
    //        {
    //            content.setBackground ( new Color ( 255, 200, 200 ) );
    //        }
    //        topicContent.setContent ( content );
    //
    //        return topicContent;
    //    }
    //
    //    private static void setExpanded ( ForumType forumType, String topicId, boolean expanded )
    //    {
    //        List<String> collapsedList = getCollapsedList ();
    //        if ( expanded )
    //        {
    //            collapsedList.remove ( getFullTopicId ( forumType, topicId ) );
    //        }
    //        else
    //        {
    //            collapsedList.add ( getFullTopicId ( forumType, topicId ) );
    //        }
    //        saveCollapsedList ( collapsedList );
    //    }
    //
    //    private static boolean isExpanded ( ForumType forumType, String topicId )
    //    {
    //        return !getCollapsedList ().contains ( getFullTopicId ( forumType, topicId ) );
    //    }
    //
    //    private static String getFullTopicId ( ForumType forumType, String topicId )
    //    {
    //        return forumType + ":" + topicId;
    //    }
    //
    //    private static List<String> getCollapsedList ()
    //    {
    //        return SettingsManager.getSettings ( "CollapsedTopics.xml", new ArrayList<String> () );
    //    }
    //
    //    private static void saveCollapsedList ( List<String> collapsedList )
    //    {
    //        SettingsManager.setSettings ( "CollapsedTopics.xml", collapsedList );
    //    }
    //
    //    private static JComponent createParsedItemsList ( SingleTopicData topicData, boolean groupItems,
    //                                                      boolean wrapItems, boolean showItemId )
    //    {
    //        if ( topicData.getParsedItems ().size () > 0 )
    //        {
    //            // Список итемов
    //            List<ItemData> itemsData = topicData.getParsedItems ();
    //            return createParsedItemsList ( itemsData, groupItems, wrapItems, showItemId );
    //        }
    //        else
    //        {
    //            // Информационное сообщение
    //            WebLabel infoLabel;
    //            if ( topicData.getTopicType ().equals ( TopicType.closed ) )
    //            {
    //                infoLabel = new WebLabel ( "Топик закрыт", closed24 );
    //            }
    //            else if ( topicData.getTopicType ().equals ( TopicType.guild ) )
    //            {
    //                infoLabel = new WebLabel ( "Операции с гильдией", guild24 );
    //            }
    //            else
    //            {
    //                infoLabel = new WebLabel ( "Не удалось определить содержимое", info24 );
    //            }
    //
    //            if ( groupItems )
    //            {
    //                WebPanel groupPanel = new WebPanel ();
    //                TableLayout layout = new TableLayout (
    //                        new double[][]{ { 100, TableLayout.PREFERRED, TableLayout.FILL },
    //                                { TableLayout.PREFERRED } } );
    //                layout.setHGap ( 5 );
    //                layout.setVGap ( 5 );
    //                groupPanel.setLayout ( layout );
    //
    //                groupPanel.add ( new WebLabel ( "Other", WebLabel.RIGHT ), "0,0" );
    //                groupPanel.add ( new WebSeparator ( false, WebSeparator.VERTICAL ), "1,0" );
    //                groupPanel.add ( infoLabel, "2,0" );
    //
    //                groupPanel.setMargin ( 4 );
    //                return groupPanel;
    //            }
    //            else
    //            {
    //                infoLabel.setMargin ( 4 );
    //                return infoLabel;
    //            }
    //        }
    //    }
    //
    //    private static JComponent createParsedItemsList ( List<ItemData> itemsData, boolean groupItems,
    //                                                      boolean wrapItems, boolean showItemId )
    //    {
    //        if ( groupItems )
    //        {
    //            // Групирруем данные
    //            Map<ItemType, List<ItemData>> groupedData = new HashMap<ItemType, List<ItemData>> ();
    //            for ( ItemData data : itemsData )
    //            {
    //                // Находим итем
    //                Item item = RagManager.getItem ( data.getItemId () );
    //
    //                // Создаём список по типу, если необходимо
    //                if ( !groupedData.containsKey ( item.getItemType () ) )
    //                {
    //                    groupedData.put ( item.getItemType (), new ArrayList<ItemData> () );
    //                }
    //
    //                // Добавляем в него итем
    //                groupedData.get ( item.getItemType () ).add ( data );
    //            }
    //
    //            // Создаём группы
    //            double[] rows = new double[ groupedData.size () * 2 - 1 ];
    //            for ( int i = 0; i < rows.length; i++ )
    //            {
    //                rows[ i ] = TableLayout.PREFERRED;
    //            }
    //            TableLayout layout = new TableLayout (
    //                    new double[][]{ { 100, TableLayout.PREFERRED, TableLayout.FILL }, rows } );
    //            layout.setHGap ( 5 );
    //            layout.setVGap ( 5 );
    //
    //            WebPanel content = new WebPanel ( layout );
    //            content.setMargin ( 3 );
    //            content.add ( new WebSeparator ( false, WebSeparator.VERTICAL ),
    //                    "1,0,1," + ( rows.length - 1 ) );
    //
    //            int row = 0;
    //            for ( ItemType itemType : groupedData.keySet () )
    //            {
    //                content.add ( new WebLabel ( itemType.getTypeName (), WebLabel.RIGHT ),
    //                        "0," + row );
    //
    //                WebPanel typePanel = new WebPanel ( getWrapLayout ( wrapItems ) )
    //                {
    //                    public Dimension getPreferredSize ()
    //                    {
    //                        Dimension ps = super.getPreferredSize ();
    //                        ps.width = 0;
    //                        return ps;
    //                    }
    //                };
    //                for ( ItemData data : groupedData.get ( itemType ) )
    //                {
    //                    typePanel.add ( createItemView ( data, showItemId ) );
    //
    //                }
    //                content.add ( typePanel, "2," + row );
    //
    //                if ( row < rows.length - 1 )
    //                {
    //                    content.add ( new WebSeparator ( false, WebSeparator.HORIZONTAL ),
    //                            "0," + ( row + 1 ) + ",2," + ( row + 1 ) );
    //                }
    //                row += 2;
    //            }
    //
    //            return content;
    //        }
    //        else
    //        {
    //            WebPanel content = new WebPanel ( getWrapLayout ( wrapItems ) )
    //            {
    //                public Dimension getPreferredSize ()
    //                {
    //                    Dimension ps = super.getPreferredSize ();
    //                    ps.width = 0;
    //                    return ps;
    //                }
    //            };
    //            content.setMargin ( 3 );
    //            for ( ItemData data : itemsData )
    //            {
    //                content.add ( createItemView ( data, showItemId ) );
    //            }
    //            return content;
    //        }
    //    }
    //
    //    private static LayoutManager getWrapLayout ( boolean wrapItems )
    //    {
    //        WrapFlowLayout wrapFlowLayout = new WrapFlowLayout ( false, 15, 4 );
    //        wrapFlowLayout.setWrapEachComponent ( wrapItems );
    //        return wrapFlowLayout;
    //        //        return wrapItems.isSelected () ?
    //        //                new VerticalFlowLayout ( VerticalFlowLayout.TOP, 4, 4, true, false ) :
    //        //                new WrapFlowLayout ( false, 15, 4 );
    //    }
    //
    //    private static JComponent createItemView ( ItemData data, boolean showItemId )
    //    {
    //        WebPanel view = new WebPanel ();
    //        view.setLayout ( new HorizontalFlowLayout ( 4, false ) );
    //
    //        // Добавляем представление итема
    //        view.add ( RagUtils.createItemInfoLink ( data ) );
    //
    //        // Добавляем представление карт
    //        List<String> cardIds = data.getCardIds ();
    //        if ( cardIds != null && cardIds.size () > 0 )
    //        {
    //            view.add ( SwingUtils.fontSize ( new WebLabel ( "[" ), 14 ) );
    //
    //            List<String> addedIds = new ArrayList<String> ();
    //            for ( int i = 0; i < cardIds.size (); i++ )
    //            {
    //                String id = cardIds.get ( i );
    //
    //                // Пропускаем повторные карты, они уже были обработаны при первом вхождении
    //                if ( addedIds.contains ( id ) )
    //                {
    //                    continue;
    //                }
    //
    //                // Вычисляем количество одинаковых карт с данным ID
    //                int amount = RagUtils.getCardsAmount ( id, cardIds );
    //                addedIds.add ( id );
    //
    //                // Добавляем описание карты
    //                WebLinkLabel cardLink = RagUtils.createItemInfoLink ( id );
    //                if ( amount > 1 )
    //                {
    //                    // Добавляем кол-во карт данного типа
    //                    view.add ( new GroupPanel ( new WebLabel ( " " + amount + "x" ), cardLink ) );
    //                }
    //                else
    //                {
    //                    // Просто добавляем описание карты
    //                    view.add ( cardLink );
    //                }
    //
    //                if ( data.getSlotCount () != null && data.getSlotCount () < cardIds.size () &&
    //                        i < cardIds.size () - 1 && RagUtils.isAnyCardsLeft ( cardIds, addedIds ) )
    //                {
    //                    view.add ( new WebLabel ( " или " ) );
    //                }
    //            }
    //
    //            view.add ( SwingUtils.fontSize ( new WebLabel ( "]" ), 14 ) );
    //        }
    //
    //        // Добавляем ссылку на копирование ID итема
    //        if ( showItemId )
    //        {
    //            view.add ( RagUtils.createIdLink ( data.getItemId () ) );
    //        }
    //
    //        return view;
    //    }
}